"""
PyMiner函数库
================

一、函数库建设方案概要
---------------------------

PyMiner旨在通过**面向过程**的方式提供大量的稳定可用的函数。
用户在使用PyMiner的时候不需要学习面向对象等复杂的编程知识，
仅在学习流程控制及函数的情况下即可完成日常的工作。

Python社区存在大量的优质第三方包，
但长期以来缺乏整合，也缺乏好用的界面。
PyMiner将主要对社区的算法进行整合，
提供稳定可用的接口。

项目初期阶段，函数库与主库置于git仓库下，
后期可考虑将其从主库中移出，单独构建算法git仓库。
但是各子库不再拆分，否则将丧失 ``PyMiner`` 的官方认证的特性。
各算法工程师如已有独立的 ``pypi`` 开源算法包，
如可以请在函数库中提供兼容接口，
如不可以则需要用户手动导入，
``algorithms.__init__`` 不会从第三方位置导入命名空间。

二、函数规范
----------------

目前方案还在初步阶段，需要听取各位的意见。
目前本程序包内的算法等均不保证稳定性。
目前仍未形成稳定的规范，在实现基本功能之后再补齐规范内容。

在[这里](./linear_algebra/开发流程.md)有一个参考的实践，
建议您读一读。

文件结构
^^^^^^^^^^^^^

采用二级结构进行组织，即 ``algorithms/package/function`` 结构。
在 ``algorithms`` 文件夹下为多个子包，即子文件夹，
每一个子包用于解决一类问题，例如绘图、线性代数运算。
在子包内为多个 ``*.py`` 模块，每一个模块都是一个函数。

各子包需命名空间，以表示该包有哪些函数可以导出，
以方便在顶层包的 ``__init__`` 中将对各个子包进行命名空间的导入。
具体的代码可以参考 ``linear_algebra`` 算法包。

在用户空间中，将会使用
``from pyminer_algorithms import *``
语句进行函数列表的导入。

目前为了方便，没有采用这个做法，而是直接将所有的函数导入命名空间。
这样存在一个问题，就是用户的变量可能会覆盖我们的函数，
这需要在用户删除该变量后重新导入函数。

开发指南
^^^^^^^^^^^^^

在进行开发前，请参考 ``pyminer_algorithms/linear_algebra`` 算法子包的开发风格。
如您有更好的建议也欢迎探讨。

作为函数库的开发者，首先需要了解基本的开源社区规范。
请严格遵循PEP8代码风格指南，并采用reStructured注释规范。
测试框架采用 ``pytest`` 。

请在注释中写清各个参数的含义，
参数的说明请参考 ``reStructured`` 规范，
当然也可以参考 ``linear_algebra`` 线性代数算法包的写法。

在完成函数的设计后，请在同文件夹内创建同名的 ``.md`` 文件，
即该函数的帮助文档。
请同时在 ``tests`` 文件夹下创建对应的测试文件，
即该函数的测试用例。

算法包也同时需要提供一个总帮助文档，用于介绍该包的含义。

帮助文档中需要的图片可以参考 ``linear_algebra`` 包的做法。

数据结构
^^^^^^^^^^^^

算法的第一等数据结构目前考虑为以下几种：

``int`` , ``float`` , ``str`` , ``numpy.ndarray`` , ``pandas.DataFrame`` 。

如有其他需求请具体讨论。

每增加一种数据结构，都会增加用户的学习成本。
因此在添加新的数据结构时务必要慎之又慎。

关于 ``List[int]`` 等复合结构不考虑支持，
这种完全可以采用 ``array(data, type=int)`` 来实现。

算法来源
^^^^^^^^^^^^

在项目初期阶段仍以导入现有的成熟的开源包为主。
核心计算框架采用 ``numpy`` ，
目前的绘图框架采用 ``matplotlib`` ，
数值计算框架采用 ``scipy`` ，
符号运算框架采用 ``sympy`` ，
统计学框架采用 ``pandas`` 。

函数命名及参数
^^^^^^^^^^^^^^^^^

同一个算法往往有多种命名方式，
``python`` 、 ``R`` 、 ``Matlab`` 都有自己的命名习惯。
在 ``PyMiner`` 中，为了尽可能保持对大数用户的友好，
采用 ``python`` 进行函数的命名，并采用 ``matlab`` 和 ``R`` 的函数别名。

函数名仅表示功能，不包含算法，
算法需要通过 ``method`` 关键字参数进行指定，
例如是采用一阶算法还是二阶算法，
可以通过 ``method="linear"`` 或者 ``method="cubic"`` 进行指定。
算法的命名也需要同时考虑多种语言的兼容。
函数的命名尽量选用长命名。
对于极为重要的函数（如求行列式的det）可以添加一个短的别名。

函数参数采用位置参数与关键字参数相结合的方法。
python的函数参数是比较优雅的实现方法，
我们可以直接沿用其标准。
请设计算法时，除必要参数外，均设置默认参数。

三、开发优先级及主要负责人
------------------------------

拟开发序列：
^^^^^^^^^^^^^^^

目前已完成矩阵及线性代数程序包的基本功能，
后续将进入长期打磨的阶段。
请各位算法工程师积极贡献代码，积极讨论需求。
全面而好用的函数库的实现离不开每一个人的努力，
``sum(每个人的一点点付出)==项目的飞跃`` ，。

#. 矩阵及线性代数运算 (linear_algebra): panhaoyu
#. 二维绘图
#. 拟合
#. 数据导入导出
#. 优化
#. 数值微积分
#. 概率与统计

符号运算部分暂缓开发，因目前对 ``sympy`` 的支持尚存在问题。

行业库序列
^^^^^^^^^^^

#. 图像处理
#. SIMULINK
#. 机器学习
#. 有限单元法
#. 其他行业库

目前各子包均需要有人主导，请可以参与的朋友积极主导算法包的开发。
"""

from .linear_algebra import *
from .pyminer_util import *
# 在通过 ``from sub_package import *`` 导入的过程中，会将 ``sub_package`` 本身也导入到 ``algorithms`` 总包的命名空间中。
# 以 ``linear_algebra`` 为例，我们需要的是 ``linear_algebra.array`` 等函数，而不是 ``linear_algebra`` 本身。
# 因此我们并不希望将 ``linear_algebra`` 引入到 ``pyminer`` 的命名空间中。
# __all__就是用于控制 ``from package import *`` 语句需要导入哪些变量的。
# 下面的这个 ``__all__`` 的主要作用是，分析局部命名空间内的所有变量，判断有哪些变量需要导入到命名空间中。
# 可以导入到命名空间中的变量的要求目前有两点：
# 1. 变量是可以调用的，也就是 ``callable(x) == True`` ；
# 1. 函数名不以下划线 ``_`` 开头，也就是 ``_array`` 不会被导入而 ``array`` 会被导入。
# 为了避免在运算的过程中引入新的变量名，所有的内容采用闭包进行操作，通过 ``lambda`` 匿名函数避免对命名空间产生污染。
__all__ = (
    lambda items: [
        k
        for k, v in items
        if callable(v) and (not k.startswith('_'))
    ]
)(locals().items())
